package com.example.javatest.TioTest.client;/**
 * @author wangXiao
 */

import com.example.javatest.TioTest.Mypacket;
import org.tio.client.intf.ClientAioHandler;
import org.tio.core.ChannelContext;
import org.tio.core.TioConfig;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;

import java.nio.ByteBuffer;

/**
 * @Description: TODO
 * @Author wangXiao
 * @Date 2024/3/15 
 **/
public class MyClientAioHandler implements ClientAioHandler {

    private static Mypacket heartbeatPacket = new Mypacket();


    /**
     * 解码：把接收到的ByteBuffer，解码成应用可以识别的业务消息包
     * 总的消息结构：
     * 1.包总长度：包总长度占4位，高位在前，低位在后
     * 2.业务包长度：业务包长度占2位，高位在前，低位在后
     * 3.业务包：业务数据包，此包中包含了业务信息，比如数据库的IP，端口，数据库名称等，例如：
     * { 
     * "clientType": "oci",
     * "clientVersion": "11g",
     * "enCodeing": "gbk",
     * "dbType": "oracle",
     * "dbIp": "10.1.198.67",
     * "dbPort": "1521"  ,
     * "dbName": "aiuap4a"
     * "systemType": "linux"
     * }
     * 4.  数据包长度：数据包长度占4位，高位在前，低位在后
     * 5.  数据包：数据库的完整的数据包
     */
    @Override
    public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws AioDecodeException {
        // 收到的数据组不了业务包，则返回null以告诉框架数据不够
        if (readableLength < Mypacket.HEADER_LENGTH) {
            return null;
        }

        // 读取消息体的长度
        int bodyLength = buffer.getInt();

        // 数据不正确，则抛出AioDecodeException异常
        if (bodyLength < 0) {
            throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right, remote:" + channelContext.getClientNode());
        }

        // 计算本次需要的数据长度
        int neededLength = Mypacket.HEADER_LENGTH + bodyLength;
        // 收到的数据是否足够组包
        int isDataEnough = readableLength - neededLength;
        // 不够消息体长度(剩下的buffe组不了消息体)
        if (isDataEnough < 0) {
            return null;
        }
        // 组包成功
        else {
            Mypacket imPacket = new Mypacket();
            if (bodyLength > 0) {
                byte[] dst = new byte[bodyLength];
                buffer.get(dst);
                imPacket.setBody(dst);
            }
            return imPacket;
        }
    }

    @Override
    public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
        Mypacket helloPacket = (Mypacket) packet;
        byte[] body = helloPacket.getBody();
        int bodyLen = 0;
        if (body != null) {
            bodyLen = body.length;
        }

        // bytebuffer的总长度是 = 消息头的长度 + 消息体的长度
        int allLen = Mypacket.HEADER_LENGTH + bodyLen;
        // 创建一个新的bytebuffer
        ByteBuffer buffer = ByteBuffer.allocate(allLen);
        // 设置字节序
        buffer.order(tioConfig.getByteOrder());

        // 写入消息头----消息头的内容就是消息体的长度
        buffer.putInt(bodyLen);

        // 写入消息体
        if (body != null) {
            buffer.put(body);
        }
        return buffer;
    }

    /**
     * 处理消息
     */
    @Override
    public void handler(Packet packet, ChannelContext channelContext) throws Exception {
        Mypacket helloPacket = (Mypacket) packet;
        byte[] body = helloPacket.getBody();
        if (body != null) {
            String str = new String(body, Mypacket.CHAR_SET);
            System.out.println("收到消息：" + str);
        }
    }

    /**
     * 此方法如果返回null，框架层面则不会发心跳；如果返回非null，框架层面会定时发本方法返回的消息包
     */
    @Override
    public Packet heartbeatPacket(ChannelContext channelContext) {
        return heartbeatPacket;
    }
}
